/**
 * Ext.ux.Translator
 * Translation Singleton which translates any string from the base language (UK English by default),
 * to any other language.  Usage:
 * Ext.ux.Translator.translate('fr', "My test string"); // returns whatever the french for that is...
 *
 * We can also set a default translate language, which will then be used as the language to translate
 * to if we only supply one argument to .translate:
 * Ext.ux.Translator.setTranslateLanguage('fr');
 * Ext.ux.Translator.translate("My test string"); // returns the same as above
 */
Ext.ux.Translator = function() {

	/**
	 * Maintains a hash of all languages and their ISO codes
	 */
	var languages = {
		'en-GB'	: {
			name			: 'UK English',
			translations	: {}
		}
	};

	/**
	 * The default language the Translator will use, if no other language
	 * has been specified.
	 */
	var defaultLanguage = user_language || 'en-GB';

	/**
	 * Object which will be populated with any language loading errors
	 */
	var translationErrors = {
		languageErrors	: {}
	};

	return {

		/**
		 * Returns the translation errors
		 * @return {Object} Translation errors
		 */
		getErrors					: function() {
			return translationErrors;
		},

		/**
		* Returns the current default language
		*/
		getDefaultLanguage			: function() {
			return defaultLanguage;
		},

		/**
		 * Returns the loaded languages
		 */
		getLanguages				: function() {
			return languages;
		},

		/**
		 * Translates the given string into the language identified by the ISO code.
		 * Always translates an English string into a foreign language string.
		 * This method also accepts a single argument (the string to be translated), so long
		 * as setTranslateLanguage() has already been called (see {@see Ext.ux.Translator.setTranslateLanguage})
		 * @param {String} key The key of the string to translate from English to another language
		 * @param {Object} args Arguments to be passed to an XTemplate
		 * @param {Boolean} error Set true if you want to return a boolean if not found
		 * @return {String} The translated string
		 */
		translate					: function(key, args, isoCode, error) {
			var isoCode = isoCode || defaultLanguage;
			var language = languages[isoCode];
			var args = args || {};

			if (!key) {
				return;
			} // nothing to translate...

			// if either the language or the key is not available. if this happens, just return the key
			// surrounded by square brackets
			if (!language || !languages[isoCode].translations[key]) {
				// Check if the default isoCode has been entered into the translation errors object
				if (!translationErrors.languageErrors[isoCode]) {
					translationErrors.languageErrors[isoCode] = [];
				};

				// Push the key intos the language errors array
				translationErrors.languageErrors[isoCode].push(key);

				if (error === true)
					return false;
				else
					return "[" + key + "]";
			};

			// Get the translation
			var translation = languages[isoCode].translations[key];

			switch (typeof translation) {
				case 'string' :
					return translation;
				case 'object' :
					return translation.apply(args);
			}
		},

		/**
		 * Registers a language with its ISO code, full name and optional translations
		 * @param {String} isoCode The ISO code for this language
		 * @param {String} languageName The full name for this language (should be in language itself (e.g. Francais not French))
		 * @param {Object} translations An optional object of key:value pairs for this language
		 */
		registerLanguage			: function(isoCode, languageName,
				translations) {
			var translations = translations || {};

			// check if the language is already defined. if it is already defined we
			// do not need to add the iso code
			if (!languages[isoCode]) {
				languages[isoCode] = {
					name			: languageName,
					translations	: {}
				};
			}

			// add the translations for the specified iso code
			Ext.ux.Translator.addTranslationsForLanguage(isoCode, translations);
		},

		/**
		 * Changes the default language from en-GB to the specified isoCode.
		 * @param {String} isoCode The ISO code for this language
		 */
		setTranslateLanguage		: function(isoCode) {
			if (isoCode) {
				// check if the isoCode is available
				if (languages[isoCode]) {
					defaultLanguage = isoCode;
				} else {
					return false;
				}
			} else {
				return false;
			}
		},

		/**
		 * Adds extra translations for an already defined language
		 * @param {String} isoCode The ISO code for this language
		 * @param {Object} translations An object of key:value pairs for this language
		 * @param {Boolean} overwrite If true, ALL old translations will be overwritten. if false
		 *                            the old translations which do not have NEW values will be
		 *                            kept.
		 */
		addTranslationsForLanguage	: function(isoCode, translations, overwrite) {
			// check if both the isoCode and translations object are defined
			if (isoCode && translations) {
				// we need to check if all the english keys has been defined in every other
				// registered language
				if (isoCode != 'en-GB') {
					var errors = [];

					// loop through each of the english translation keys and check if they are
					// in the new language
					for (key in languages['en-GB'].translations) {
						if (!translations[key]) {
							errors.push(key);
						}
					};

					// Check if any errors for this isoCode already exist
					if (!translationErrors.languageErrors[isoCode]) {
						translationErrors.languageErrors[isoCode] = [];
					};

					// Add the errors
					translationErrors.languageErrors[isoCode] = errors;
				}

				// check if we want to overwrite the current translations
				if (overwrite) {
					languages[isoCode].translations = translations;
				} else {
					Ext.apply(languages[isoCode].translations, translations);
				}
			}
		}
	};
}();
